using Microsoft.Extensions.Logging;
using System.Text;
using Uantek.Device.Communication.Models;
using Uantek.Device.Communication.Protocols.Transports;

namespace Uantek.Device.Communication.Protocols.Modbus
{
    /// <summary>
    /// Modbus TCP传输实现
    /// </summary>
    public class ModbusTcpTransport : TcpTransport
    {
        /// <summary>
        /// Modbus TCP头部长度
        /// </summary>
        private const int ModbusTcpHeaderLength = 6;

        /// <summary>
        /// 事务标识符（递增）
        /// </summary>
        private ushort _transactionId = 0;

        /// <summary>
        /// 协议标识符（固定为0）
        /// </summary>
        private const ushort ProtocolId = 0;

        /// <summary>
        /// 单元标识符（从站地址）
        /// </summary>
        public byte UnitId { get; set; } = 1;

        /// <summary>
        /// 传输类型
        /// </summary>
        public override string TransportType => "ModbusTCP";

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="logger">日志记录器</param>
        public ModbusTcpTransport(ILogger<ModbusTcpTransport>? logger = null) : base(logger)
        {
        }

        /// <summary>
        /// 发送数据的具体实现（重写以添加Modbus TCP头部）
        /// </summary>
        /// <param name="data">数据</param>
        /// <returns>发送结果</returns>
        protected override CommunicationResult SendDataInternal(byte[] data)
        {
            try
            {
                LogDebug("发送Modbus TCP数据，原始长度: {Length}，数据: {Data}", data.Length, Convert.ToHexString(data));

                // 构建Modbus TCP帧
                var modbusTcpFrame = BuildModbusTcpFrame(data);

                LogDebug("发送Modbus TCP帧，总长度: {Length}，帧数据: {Data}", modbusTcpFrame.Length, Convert.ToHexString(modbusTcpFrame));

                // 调用基类的发送方法
                return base.SendDataInternal(modbusTcpFrame);
            }
            catch (Exception ex)
            {
                LogError(ex, "发送Modbus TCP数据时发生异常");
                return CommunicationResult.CreateFailure($"发送Modbus TCP数据异常: {ex.Message}", "SendException", ex);
            }
        }

        /// <summary>
        /// 发送Modbus命令并等待响应
        /// </summary>
        /// <param name="functionCode">功能码</param>
        /// <param name="data">数据部分</param>
        /// <param name="timeout">超时时间（毫秒）</param>
        /// <returns>响应数据</returns>
        public async Task<CommunicationResult<byte[]>> SendModbusCommandAsync(byte functionCode, byte[] data, int timeout = 5000)
        {
            try
            {
                LogDebug("发送Modbus命令，功能码: 0x{FunctionCode:X2}，数据长度: {Length}", functionCode, data.Length);

                // 构建Modbus PDU（协议数据单元）
                var pdu = new List<byte> { functionCode };
                pdu.AddRange(data);

                // 发送数据并等待响应
                var result = await SendAndReceiveAsync(pdu.ToArray(), timeout);

                if (result.Success && result.Data != null)
                {
                    // 解析Modbus TCP响应
                    var modbusPdu = ParseModbusTcpResponse(result.Data);
                    if (modbusPdu != null)
                    {
                        LogDebug("Modbus命令响应成功，功能码: 0x{FunctionCode:X2}，响应长度: {Length}", 
                            functionCode, modbusPdu.Length);
                        return CommunicationResult<byte[]>.CreateSuccess(modbusPdu, "Modbus命令执行成功");
                    }
                    else
                    {
                        return CommunicationResult<byte[]>.CreateFailure("Modbus TCP响应解析失败", "ResponseParsingFailed");
                    }
                }

                return CommunicationResult<byte[]>.CreateFailure(result.Message, result.ErrorCode, result.Exception);
            }
            catch (Exception ex)
            {
                LogError(ex, "发送Modbus命令时发生异常，功能码: 0x{FunctionCode:X2}", functionCode);
                return CommunicationResult<byte[]>.CreateFailure($"发送Modbus命令异常: {ex.Message}", "CommandException", ex);
            }
        }

        /// <summary>
        /// 读取线圈状态
        /// </summary>
        /// <param name="startAddress">起始地址</param>
        /// <param name="quantity">数量</param>
        /// <param name="timeout">超时时间</param>
        /// <returns>线圈状态</returns>
        public async Task<CommunicationResult<bool[]>> ReadCoilsAsync(ushort startAddress, ushort quantity, int timeout = 5000)
        {
            try
            {
                LogDebug("读取线圈状态，起始地址: {StartAddress}，数量: {Quantity}", startAddress, quantity);

                var data = new List<byte>();
                data.AddRange(BitConverter.GetBytes(SwapBytes(startAddress)));
                data.AddRange(BitConverter.GetBytes(SwapBytes(quantity)));

                var result = await SendModbusCommandAsync(ModbusProtocol.FunctionCodes.ReadCoils, data.ToArray(), timeout);

                if (result.Success && result.Data != null)
                {
                    return ParseCoilsResponse(result.Data, quantity);
                }

                return CommunicationResult<bool[]>.CreateFailure(result.Message, result.ErrorCode, result.Exception);
            }
            catch (Exception ex)
            {
                LogError(ex, "读取线圈状态时发生异常");
                return CommunicationResult<bool[]>.CreateFailure($"读取线圈状态异常: {ex.Message}", "ReadCoilsException", ex);
            }
        }

        /// <summary>
        /// 读取保持寄存器
        /// </summary>
        /// <param name="startAddress">起始地址</param>
        /// <param name="quantity">数量</param>
        /// <param name="timeout">超时时间</param>
        /// <returns>寄存器值</returns>
        public async Task<CommunicationResult<ushort[]>> ReadHoldingRegistersAsync(ushort startAddress, ushort quantity, int timeout = 5000)
        {
            try
            {
                LogDebug("读取保持寄存器，起始地址: {StartAddress}，数量: {Quantity}", startAddress, quantity);

                var data = new List<byte>();
                data.AddRange(BitConverter.GetBytes(SwapBytes(startAddress)));
                data.AddRange(BitConverter.GetBytes(SwapBytes(quantity)));

                var result = await SendModbusCommandAsync(ModbusProtocol.FunctionCodes.ReadHoldingRegisters, data.ToArray(), timeout);

                if (result.Success && result.Data != null)
                {
                    return ParseRegistersResponse(result.Data, quantity);
                }

                return CommunicationResult<ushort[]>.CreateFailure(result.Message, result.ErrorCode, result.Exception);
            }
            catch (Exception ex)
            {
                LogError(ex, "读取保持寄存器时发生异常");
                return CommunicationResult<ushort[]>.CreateFailure($"读取保持寄存器异常: {ex.Message}", "ReadHoldingRegistersException", ex);
            }
        }

        /// <summary>
        /// 读取输入寄存器
        /// </summary>
        /// <param name="startAddress">起始地址</param>
        /// <param name="quantity">数量</param>
        /// <param name="timeout">超时时间</param>
        /// <returns>寄存器值</returns>
        public async Task<CommunicationResult<ushort[]>> ReadInputRegistersAsync(ushort startAddress, ushort quantity, int timeout = 5000)
        {
            try
            {
                LogDebug("读取输入寄存器，起始地址: {StartAddress}，数量: {Quantity}", startAddress, quantity);

                var data = new List<byte>();
                data.AddRange(BitConverter.GetBytes(SwapBytes(startAddress)));
                data.AddRange(BitConverter.GetBytes(SwapBytes(quantity)));

                var result = await SendModbusCommandAsync(ModbusProtocol.FunctionCodes.ReadInputRegisters, data.ToArray(), timeout);

                if (result.Success && result.Data != null)
                {
                    return ParseRegistersResponse(result.Data, quantity);
                }

                return CommunicationResult<ushort[]>.CreateFailure(result.Message, result.ErrorCode, result.Exception);
            }
            catch (Exception ex)
            {
                LogError(ex, "读取输入寄存器时发生异常");
                return CommunicationResult<ushort[]>.CreateFailure($"读取输入寄存器异常: {ex.Message}", "ReadInputRegistersException", ex);
            }
        }

        /// <summary>
        /// 写单个线圈
        /// </summary>
        /// <param name="address">地址</param>
        /// <param name="value">值</param>
        /// <param name="timeout">超时时间</param>
        /// <returns>写入结果</returns>
        public async Task<CommunicationResult> WriteSingleCoilAsync(ushort address, bool value, int timeout = 5000)
        {
            try
            {
                LogDebug("写单个线圈，地址: {Address}，值: {Value}", address, value);

                var data = new List<byte>();
                data.AddRange(BitConverter.GetBytes(SwapBytes(address)));
                var coilValue = value ? (ushort)0xFF00 : (ushort)0x0000;
                data.AddRange(BitConverter.GetBytes(SwapBytes(coilValue)));

                var result = await SendModbusCommandAsync(ModbusProtocol.FunctionCodes.WriteSingleCoil, data.ToArray(), timeout);

                if (result.Success)
                {
                    LogDebug("写单个线圈成功，地址: {Address}，值: {Value}", address, value);
                    return CommunicationResult.CreateSuccess("写单个线圈成功");
                }

                return CommunicationResult.CreateFailure(result.Message, result.ErrorCode, result.Exception);
            }
            catch (Exception ex)
            {
                LogError(ex, "写单个线圈时发生异常");
                return CommunicationResult.CreateFailure($"写单个线圈异常: {ex.Message}", "WriteSingleCoilException", ex);
            }
        }

        /// <summary>
        /// 写单个寄存器
        /// </summary>
        /// <param name="address">地址</param>
        /// <param name="value">值</param>
        /// <param name="timeout">超时时间</param>
        /// <returns>写入结果</returns>
        public async Task<CommunicationResult> WriteSingleRegisterAsync(ushort address, ushort value, int timeout = 5000)
        {
            try
            {
                LogDebug("写单个寄存器，地址: {Address}，值: {Value}", address, value);

                var data = new List<byte>();
                data.AddRange(BitConverter.GetBytes(SwapBytes(address)));
                data.AddRange(BitConverter.GetBytes(SwapBytes(value)));

                var result = await SendModbusCommandAsync(ModbusProtocol.FunctionCodes.WriteSingleRegister, data.ToArray(), timeout);

                if (result.Success)
                {
                    LogDebug("写单个寄存器成功，地址: {Address}，值: {Value}", address, value);
                    return CommunicationResult.CreateSuccess("写单个寄存器成功");
                }

                return CommunicationResult.CreateFailure(result.Message, result.ErrorCode, result.Exception);
            }
            catch (Exception ex)
            {
                LogError(ex, "写单个寄存器时发生异常");
                return CommunicationResult.CreateFailure($"写单个寄存器异常: {ex.Message}", "WriteSingleRegisterException", ex);
            }
        }

        /// <summary>
        /// 写多个寄存器
        /// </summary>
        /// <param name="startAddress">起始地址</param>
        /// <param name="values">值数组</param>
        /// <param name="timeout">超时时间</param>
        /// <returns>写入结果</returns>
        public async Task<CommunicationResult> WriteMultipleRegistersAsync(ushort startAddress, ushort[] values, int timeout = 5000)
        {
            try
            {
                LogDebug("写多个寄存器，起始地址: {StartAddress}，数量: {Quantity}", startAddress, values.Length);

                var data = new List<byte>();
                data.AddRange(BitConverter.GetBytes(SwapBytes(startAddress)));
                data.AddRange(BitConverter.GetBytes(SwapBytes((ushort)values.Length)));
                data.Add((byte)(values.Length * 2)); // 字节数

                foreach (var value in values)
                {
                    data.AddRange(BitConverter.GetBytes(SwapBytes(value)));
                }

                var result = await SendModbusCommandAsync(ModbusProtocol.FunctionCodes.WriteMultipleRegisters, data.ToArray(), timeout);

                if (result.Success)
                {
                    LogDebug("写多个寄存器成功，起始地址: {StartAddress}，数量: {Quantity}", startAddress, values.Length);
                    return CommunicationResult.CreateSuccess("写多个寄存器成功");
                }

                return CommunicationResult.CreateFailure(result.Message, result.ErrorCode, result.Exception);
            }
            catch (Exception ex)
            {
                LogError(ex, "写多个寄存器时发生异常");
                return CommunicationResult.CreateFailure($"写多个寄存器异常: {ex.Message}", "WriteMultipleRegistersException", ex);
            }
        }

        #region 私有方法

        /// <summary>
        /// 构建Modbus TCP帧
        /// </summary>
        /// <param name="pdu">协议数据单元</param>
        /// <returns>Modbus TCP帧</returns>
        private byte[] BuildModbusTcpFrame(byte[] pdu)
        {
            var frame = new List<byte>();

            // 事务标识符（2字节）
            var currentTransactionId = GetNextTransactionId();
            frame.AddRange(BitConverter.GetBytes(SwapBytes(currentTransactionId)));

            // 协议标识符（2字节，固定为0）
            frame.AddRange(BitConverter.GetBytes(SwapBytes(ProtocolId)));

            // 长度字段（2字节）= 单元标识符（1字节） + PDU长度
            var length = (ushort)(1 + pdu.Length);
            frame.AddRange(BitConverter.GetBytes(SwapBytes(length)));

            // 单元标识符（1字节）
            frame.Add(UnitId);

            // PDU（协议数据单元）
            frame.AddRange(pdu);

            return frame.ToArray();
        }

        /// <summary>
        /// 解析Modbus TCP响应
        /// </summary>
        /// <param name="response">响应数据</param>
        /// <returns>Modbus PDU</returns>
        private byte[]? ParseModbusTcpResponse(byte[] response)
        {
            try
            {
                if (response.Length < ModbusTcpHeaderLength + 1)
                {
                    LogWarning("Modbus TCP响应长度不足，最小长度: {MinLength}，实际长度: {ActualLength}", 
                        ModbusTcpHeaderLength + 1, response.Length);
                    return null;
                }

                // 解析头部
                var transactionId = SwapBytes(BitConverter.ToUInt16(response, 0));
                var protocolId = SwapBytes(BitConverter.ToUInt16(response, 2));
                var length = SwapBytes(BitConverter.ToUInt16(response, 4));
                var unitId = response[6];

                LogDebug("Modbus TCP响应头部，事务ID: {TransactionId}，协议ID: {ProtocolId}，长度: {Length}，单元ID: {UnitId}", 
                    transactionId, protocolId, length, unitId);

                // 验证协议标识符
                if (protocolId != ProtocolId)
                {
                    LogWarning("Modbus TCP协议标识符不匹配，期望: {Expected}，实际: {Actual}", ProtocolId, protocolId);
                    return null;
                }

                // 验证单元标识符
                if (unitId != UnitId)
                {
                    LogWarning("Modbus TCP单元标识符不匹配，期望: {Expected}，实际: {Actual}", UnitId, unitId);
                }

                // 验证长度
                var expectedLength = response.Length - ModbusTcpHeaderLength;
                if (length != expectedLength)
                {
                    LogWarning("Modbus TCP长度字段不匹配，期望: {Expected}，实际: {Actual}", expectedLength, length);
                }

                // 提取PDU
                var pduLength = response.Length - ModbusTcpHeaderLength - 1; // 减去单元标识符
                var pdu = new byte[pduLength];
                Array.Copy(response, ModbusTcpHeaderLength + 1, pdu, 0, pduLength);

                return pdu;
            }
            catch (Exception ex)
            {
                LogError(ex, "解析Modbus TCP响应时发生异常");
                return null;
            }
        }

        /// <summary>
        /// 解析线圈响应
        /// </summary>
        /// <param name="pdu">协议数据单元</param>
        /// <param name="expectedQuantity">期望的线圈数量</param>
        /// <returns>线圈状态</returns>
        private CommunicationResult<bool[]> ParseCoilsResponse(byte[] pdu, ushort expectedQuantity)
        {
            try
            {
                if (pdu.Length < 2)
                {
                    return CommunicationResult<bool[]>.CreateFailure("线圈响应数据长度不足", "InsufficientData");
                }

                var functionCode = pdu[0];
                var byteCount = pdu[1];

                // 检查是否为异常响应
                if ((functionCode & 0x80) != 0)
                {
                    var exceptionCode = pdu[1];
                    return CommunicationResult<bool[]>.CreateFailure($"Modbus异常响应，异常码: 0x{exceptionCode:X2}", "ModbusException");
                }

                var coils = new List<bool>();
                for (int i = 0; i < byteCount; i++)
                {
                    var coilByte = pdu[2 + i];
                    for (int bit = 0; bit < 8 && coils.Count < expectedQuantity; bit++)
                    {
                        coils.Add((coilByte & (1 << bit)) != 0);
                    }
                }

                return CommunicationResult<bool[]>.CreateSuccess(coils.ToArray(), "线圈状态读取成功");
            }
            catch (Exception ex)
            {
                LogError(ex, "解析线圈响应时发生异常");
                return CommunicationResult<bool[]>.CreateFailure($"解析线圈响应异常: {ex.Message}", "ParseException", ex);
            }
        }

        /// <summary>
        /// 解析寄存器响应
        /// </summary>
        /// <param name="pdu">协议数据单元</param>
        /// <param name="expectedQuantity">期望的寄存器数量</param>
        /// <returns>寄存器值</returns>
        private CommunicationResult<ushort[]> ParseRegistersResponse(byte[] pdu, ushort expectedQuantity)
        {
            try
            {
                if (pdu.Length < 2)
                {
                    return CommunicationResult<ushort[]>.CreateFailure("寄存器响应数据长度不足", "InsufficientData");
                }

                var functionCode = pdu[0];
                var byteCount = pdu[1];

                // 检查是否为异常响应
                if ((functionCode & 0x80) != 0)
                {
                    var exceptionCode = pdu[1];
                    return CommunicationResult<ushort[]>.CreateFailure($"Modbus异常响应，异常码: 0x{exceptionCode:X2}", "ModbusException");
                }

                var registers = new List<ushort>();
                for (int i = 0; i < byteCount; i += 2)
                {
                    var registerValue = BitConverter.ToUInt16(pdu, 2 + i);
                    registers.Add(SwapBytes(registerValue));
                }

                return CommunicationResult<ushort[]>.CreateSuccess(registers.ToArray(), "寄存器值读取成功");
            }
            catch (Exception ex)
            {
                LogError(ex, "解析寄存器响应时发生异常");
                return CommunicationResult<ushort[]>.CreateFailure($"解析寄存器响应异常: {ex.Message}", "ParseException", ex);
            }
        }

        /// <summary>
        /// 获取下一个事务ID
        /// </summary>
        /// <returns>事务ID</returns>
        private ushort GetNextTransactionId()
        {
            return ++_transactionId;
        }

        /// <summary>
        /// 大端序转小端序
        /// </summary>
        /// <param name="value">值</param>
        /// <returns>转换后的值</returns>
        private static ushort SwapBytes(ushort value)
        {
            return (ushort)((value << 8) | (value >> 8));
        }

        #endregion

        #region 公共方法

        /// <summary>
        /// 设置单元标识符
        /// </summary>
        /// <param name="unitId">单元标识符</param>
        public void SetUnitId(byte unitId)
        {
            UnitId = unitId;
            LogDebug("设置Modbus单元标识符: {UnitId}", unitId);
        }

        /// <summary>
        /// 获取当前事务ID
        /// </summary>
        /// <returns>当前事务ID</returns>
        public ushort GetCurrentTransactionId()
        {
            return _transactionId;
        }

        /// <summary>
        /// 重置事务ID
        /// </summary>
        public void ResetTransactionId()
        {
            _transactionId = 0;
            LogDebug("重置Modbus事务ID");
        }

        /// <summary>
        /// 构建连接信息（重写）
        /// </summary>
        /// <param name="connectionParameters">连接参数</param>
        /// <returns>连接信息</returns>
        protected override string BuildConnectionInfo(Dictionary<string, object> connectionParameters)
        {
            var host = GetParameter<string>(connectionParameters, "Host", "127.0.0.1");
            var port = GetParameter<int>(connectionParameters, "Port", 502);
            return $"ModbusTCP://{host}:{port}?unit={UnitId}";
        }

        #endregion
    }
}